package cn.learn.designpattern.singleton;

/*
 * 只有在要明确实现 lazy loading 效果时，才会使用第 3 种登记方式
 * 如果涉及到反序列化创建对象时，可以尝试使用第 4 种枚举方式
 * 如果有其他特殊的需求，可以考虑使用第 2 种双检锁方式。
 * 现在推荐枚举单例模式，最完美
 */

/**
 * 单例模式（饿汉式）
 * 这种方式比较常用，但容易产生垃圾对象
 * 优点：线程安全，没有加锁，执行效率会提高。
 * 缺点：不是Lazy，类加载时就初始化，浪费内存。
 *
 * @author huangyezhan
 * @version 1.0
 * @date 2020年09月08日18:23
 */
public class Singleton1 {
    private static final Singleton1 instance = new Singleton1();

    private Singleton1() {
    }

    public static Singleton1 getInstance() {
        return instance;
    }
}

/**
 * 单例模式（双检锁/双重校验锁）
 * <p>
 * 优点：Lazy、线程安全，这种方式采用双锁机制，安全且在多线程情况下能保持高性能。
 * 缺点：第一次加载时反应不快，可能还存在反射攻击或者反序列化攻击
 * getInstance() 的性能对应用程序很关键。
 */
class Singleton2 {
    private volatile static Singleton2 singleton;

    private Singleton2() {
    }

    public static Singleton2 getSingleton() {
        if (singleton == null) {
            synchronized (Singleton2.class) {
                if (singleton == null) {
                    singleton = new Singleton2();
                }
            }
        }
        return singleton;
    }
}

/**
 * 单例模式（登记式/静态内部类）
 * 优点：Lazy，线程安全，
 * 缺点：第一次加载时反应不快，可能还存在反射攻击或者反序列化攻击
 */
class Singleton3 {
    private Singleton3() {
    }

    private static class SingletonHolder {
        private static final Singleton3 INSTANCE = new Singleton3();
    }

    public static Singleton3 getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

/**
 * 单例模式（枚举）
 * <p>
 * 不是 Lazy
 * 线程安全
 * <p/>
 * 这种实现方式还没有被广泛采用，但这是实现单例模式的最佳方法。它更简洁，自动支持序列化机制，绝对防止多次实例化
 * 它不仅能避免多线程同步问题，而且还自动支持序列化机制，防止反序列化重新创建新的对象，绝对防止多次实例化
 */
enum Singleton4 {
    /**
     * 实例
     */
    INSTANCE;

    public String whateverMethod() {
        // TODO do something
        return "";
    }

}
